﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Brain.Editor
{
    public class PickingManager3D_PhysicsRayTesting : IPickingManager3D
    {
        /// <summary>
        /// If the Picking Manager is currently manipulating the Selected Object
        /// </summary>
        public bool Manipulating { get; protected set; }

        /// <summary>
        /// The Picked Object
        /// </summary>
        public IPickedObject SelectedWorldObject { get; set; }

        /// <summary>
        /// The current Manipulation mode
        /// </summary>
        public ManipulationMode3D Mode { get; set; }

        /// <summary>
        /// If it should Update
        /// </summary>
        public bool ShouldUpdate { get; set; }

        public WorldObject XMani;
        public WorldObject YMani;
        public WorldObject ZMani;

        public event SetIPickerObject OnSelected;

        public float ScaleBefore;
        public Vector3 UnitAxis;

        #region Resources
#if WINDOWS
        Byte[] effect = new Byte[1620] { 207, 11, 240, 188, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 255, 254, 192, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 87, 111, 114, 108, 100, 0, 122, 0, 3, 0, 0, 0, 2, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 86, 105, 101, 119, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 80, 114, 111, 106, 101, 99, 116, 105, 111, 110, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 104, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 67, 111, 108, 111, 114, 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 80, 97, 115, 115, 49, 0, 0, 0, 11, 0, 0, 0, 84, 101, 99, 104, 110, 105, 113, 117, 101, 49, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 92, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 120, 1, 0, 0, 116, 1, 0, 0, 147, 0, 0, 0, 0, 0, 0, 0, 144, 1, 0, 0, 140, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 232, 1, 0, 0, 0, 2, 255, 255, 254, 255, 22, 0, 67, 84, 65, 66, 28, 0, 0, 0, 35, 0, 0, 0, 0, 2, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 28, 0, 0, 0, 112, 115, 95, 50, 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 57, 46, 50, 54, 46, 57, 53, 50, 46, 50, 56, 52, 52, 0, 254, 255, 93, 0, 80, 82, 69, 83, 1, 2, 88, 70, 254, 255, 36, 0, 67, 84, 65, 66, 28, 0, 0, 0, 91, 0, 0, 0, 1, 2, 88, 70, 1, 0, 0, 0, 28, 0, 0, 0, 0, 1, 0, 32, 88, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 56, 0, 0, 0, 72, 0, 0, 0, 67, 111, 108, 111, 114, 0, 171, 171, 1, 0, 3, 0, 1, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 120, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 57, 46, 50, 54, 46, 57, 53, 50, 46, 50, 56, 52, 52, 0, 254, 255, 12, 0, 80, 82, 83, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 18, 0, 67, 76, 73, 84, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 20, 0, 70, 88, 76, 67, 2, 0, 0, 0, 3, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 240, 240, 240, 240, 15, 15, 15, 15, 255, 255, 0, 0, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 160, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 212, 1, 0, 0, 0, 2, 254, 255, 254, 255, 63, 0, 67, 84, 65, 66, 28, 0, 0, 0, 198, 0, 0, 0, 0, 2, 254, 255, 3, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 32, 191, 0, 0, 0, 88, 0, 0, 0, 2, 0, 8, 0, 4, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 180, 0, 0, 0, 2, 0, 4, 0, 4, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 185, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 80, 114, 111, 106, 101, 99, 116, 105, 111, 110, 0, 171, 3, 0, 3, 0, 4, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 105, 101, 119, 0, 87, 111, 114, 108, 100, 0, 118, 115, 95, 50, 95, 48, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 57, 46, 50, 54, 46, 57, 53, 50, 46, 50, 56, 52, 52, 0, 171, 31, 0, 0, 2, 0, 0, 0, 128, 0, 0, 15, 144, 9, 0, 0, 3, 0, 0, 1, 128, 0, 0, 228, 144, 0, 0, 228, 160, 9, 0, 0, 3, 0, 0, 2, 128, 0, 0, 228, 144, 1, 0, 228, 160, 9, 0, 0, 3, 0, 0, 4, 128, 0, 0, 228, 144, 2, 0, 228, 160, 9, 0, 0, 3, 0, 0, 8, 128, 0, 0, 228, 144, 3, 0, 228, 160, 9, 0, 0, 3, 1, 0, 1, 128, 0, 0, 228, 128, 4, 0, 228, 160, 9, 0, 0, 3, 1, 0, 2, 128, 0, 0, 228, 128, 5, 0, 228, 160, 9, 0, 0, 3, 1, 0, 4, 128, 0, 0, 228, 128, 6, 0, 228, 160, 9, 0, 0, 3, 1, 0, 8, 128, 0, 0, 228, 128, 7, 0, 228, 160, 9, 0, 0, 3, 0, 0, 1, 192, 1, 0, 228, 128, 8, 0, 228, 160, 9, 0, 0, 3, 0, 0, 2, 192, 1, 0, 228, 128, 9, 0, 228, 160, 9, 0, 0, 3, 0, 0, 4, 192, 1, 0, 228, 128, 10, 0, 228, 160, 9, 0, 0, 3, 0, 0, 8, 192, 1, 0, 228, 128, 11, 0, 228, 160, 255, 255, 0, 0 };
#endif
#if XBOX
        Byte[] effect = new Byte[1380] {188,240,11,207,0,0,0,16,0,0,0,0,0,0,0,0,254,255,9,1,0,0,1,192,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,87,111,114,108,100,0,0,0,0,0,0,3,0,0,0,3,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,86,105,101,119,0,0,0,0,0,0,0,3,0,0,0,3,0,0,1,48,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,80,114,111,106,101,99,116,105,111,110,0,0,0,0,0,3,0,0,0,1,0,0,1,104,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,67,111,108,111,114,0,0,0,0,0,0,1,0,0,0,16,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,15,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,80,97,115,115,49,0,0,0,0,0,0,11,84,101,99,104,110,105,113,117,101,49,0,0,0,0,0,4,0,0,0,1,0,0,0,3,0,0,0,3,0,0,0,4,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,108,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,212,0,0,0,240,0,0,0,0,0,0,0,0,0,0,1,64,0,0,1,92,0,0,0,0,0,0,0,0,0,0,1,176,0,0,0,0,0,0,0,1,0,0,1,164,0,0,0,0,0,0,0,2,0,0,0,92,0,0,0,0,0,0,1,120,0,0,1,116,0,0,0,93,0,0,0,0,0,0,1,144,0,0,1,140,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,216,16,42,17,0,0,0,0,180,0,0,0,36,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,108,0,0,0,28,0,0,0,95,255,255,3,0,0,0,0,1,0,0,0,28,0,0,0,0,0,0,0,88,0,0,0,48,0,2,0,0,0,1,0,0,0,0,0,56,0,0,0,72,67,111,108,111,114,0,171,171,0,1,0,3,0,1,0,3,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,112,115,95,51,95,48,0,50,46,48,46,49,49,54,50,54,46,48,0,171,0,0,0,0,0,0,0,36,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,16,1,196,0,34,0,0,0,200,143,192,0,0,192,192,0,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,1,244,16,42,17,1,0,0,1,40,0,0,0,204,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,252,0,0,0,0,0,0,0,0,0,0,0,212,0,0,0,28,0,0,0,198,255,254,3,0,0,0,0,3,0,0,0,28,0,0,0,0,0,0,0,191,0,0,0,88,0,2,0,8,0,4,0,0,0,0,0,100,0,0,0,116,0,0,0,180,0,2,0,4,0,4,0,0,0,0,0,100,0,0,0,116,0,0,0,185,0,2,0,0,0,4,0,0,0,0,0,100,0,0,0,116,80,114,111,106,101,99,116,105,111,110,0,171,0,3,0,3,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,105,101,119,0,87,111,114,108,100,0,118,115,95,51,95,48,0,50,46,48,46,49,49,54,50,54,46,48,0,171,171,0,0,0,0,0,0,0,204,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,2,144,0,0,0,3,16,1,16,3,0,0,18,0,194,0,0,0,0,0,96,4,96,10,18,0,18,0,0,0,0,0,0,0,0,3,196,0,34,0,0,0,5,248,0,0,0,0,6,136,0,0,0,0,200,1,0,1,0,167,167,0,175,0,0,0,200,2,0,1,0,167,167,0,175,0,1,0,200,4,0,1,0,167,167,0,175,0,2,0,200,8,0,1,0,167,167,0,175,0,3,0,200,1,0,0,0,167,167,0,175,1,4,0,200,2,0,0,0,167,167,0,175,1,5,0,200,4,0,0,0,167,167,0,175,1,6,0,200,8,0,0,0,167,167,0,175,1,7,0,200,1,128,62,0,167,167,0,175,0,8,0,200,2,128,62,0,167,167,0,175,0,9,0,200,4,128,62,0,167,167,0,175,0,10,0,200,8,128,62,0,167,167,0,175,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0 };
#endif
        #endregion
        BrainModel Cylinder;
        private Effect PickingEffect;

        public RenderTarget2D PickerTarget;

        private SpriteBatch batch;

        protected PickingManager3D_PhysicsRayTesting()
        {
            batch = new SpriteBatch(Engine.Instance.GraphicsDevice);

            PresentationParameters pp = Engine.Instance.GraphicsDevice.PresentationParameters;
            PickerTarget = new RenderTarget2D(Engine.Instance.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight,
                false, SurfaceFormat.Color, DepthFormat.Depth24);

            Cylinder = ModelUtil.GenerateCylinderMesh(5, 1, 16);

#if !WINDOWS_PHONE
            PickingEffect = new Effect(Engine.Instance.GraphicsDevice, effect);
#endif

            XMani = new WorldObject();
            XMani.Scale = new Vector3(5, 1, 1);
            XMani.BoundingBox = new BoundingBox(Vector3.Zero, XMani.Scale);
            YMani = new WorldObject();
            YMani.Scale = new Vector3(1, 5, 1);
            YMani.BoundingBox = new BoundingBox(Vector3.Zero, YMani.Scale);
            ZMani = new WorldObject();
            ZMani.Scale = new Vector3(1, 1, 5);
            ZMani.BoundingBox = new BoundingBox(Vector3.Zero, ZMani.Scale);

            ShouldUpdate = true;
            ShouldDraw = true;
        }

        float RelativeScale;
        public void Update()
        {
            XMani.Rendering = WorldObjectRendering.EditorVisible;
            YMani.Rendering = WorldObjectRendering.EditorVisible;
            ZMani.Rendering = WorldObjectRendering.EditorVisible;

            XMani.Update();
            YMani.Update();
            ZMani.Update();

            XMani.BoundingBox = new BoundingBox(XMani.Position, XMani.Position + XMani.Scale);
            YMani.BoundingBox = new BoundingBox(YMani.Position, YMani.Position + YMani.Scale);
            ZMani.BoundingBox = new BoundingBox(ZMani.Position, ZMani.Position + ZMani.Scale);

            ICamera3D camera = Engine.Instance.CameraManager.Camera3D;
            GraphicsDevice device = Engine.Instance.GraphicsDevice;
            IPickedObject wo_Mani = null;
            if (!Manipulating && camera != null)
            {
                Vector2 mousePos = Engine.Instance.InputManager.GetMousePosition();
                int X = (int)mousePos.X;
                int Y = (int)mousePos.Y;
                Vector3 v;
                wo_Mani = Pick(X, Y, device.Viewport, camera, out v);
                if (Engine.Instance.InputManager.IsMouseLeftDown())
                {
                    if (wo_Mani != null &&
                        wo_Mani != this.XMani &&
                        wo_Mani != this.YMani &&
                        wo_Mani != this.ZMani &&
                        wo_Mani != this.SelectedWorldObject)
                    {
                        this.SelectedWorldObject = wo_Mani;
                        if (OnSelected != null)
                            OnSelected(wo_Mani);
                    }
                }
                UnitAxis = new Vector3(
                        wo_Mani == XMani ? 1 : 0,
                        wo_Mani == YMani ? 1 : 0,
                        wo_Mani == ZMani ? 1 : 0);
            }

            Vector3 Position = Vector3.Zero;
            float size = 30;
            RelativeScale = 5;
            float RelativeScaleOverTwo = RelativeScale / 2f;
            if (this.SelectedWorldObject != null && camera != null)
            {
                Position = SelectedWorldObject.Position;

                if (!Manipulating)
                {
                    Vector3 viewPosition = camera.Position;

                    Matrix ScaleView = Matrix.CreateLookAt(Vector3.UnitZ *
                        Vector3.Distance(viewPosition, Position), Vector3.Zero, Vector3.Up);

                    Vector3 ProjStart = Engine.Instance.GraphicsDevice.Viewport.Project(
                        Vector3.Zero, camera.Projection, ScaleView, Matrix.Identity);
                    Vector3 ProjEnd = Engine.Instance.GraphicsDevice.Viewport.Project(
                        Vector3.UnitX, camera.Projection, ScaleView, Matrix.Identity);

                    RelativeScale = size / (ProjEnd - ProjStart).Length();
                    RelativeScale *= 2;
                    RelativeScaleOverTwo = RelativeScale / 2f;

                    ScaleBefore = RelativeScale;
                }
                else
                {
                    RelativeScale = ScaleBefore;
                    RelativeScaleOverTwo = ScaleBefore / 2f;
                }

                float relative = RelativeScaleOverTwo / 2f;
                this.XMani.Scale = new Vector3(relative * 5, relative, relative);
                this.YMani.Scale = new Vector3(relative, relative * 5, relative);
                this.ZMani.Scale = new Vector3(relative, relative, relative * 5);

                if (Engine.Instance.InputManager.IsMouseLeftDown() &&
                    camera != null)
                {
                    Manipulating = true;

                    if (UnitAxis != Vector3.Zero)
                    {
                        Matrix Translation = Matrix.Identity;
                        Matrix Projection = camera.Projection;
                        Matrix View = camera.View;
                        Viewport Viewport = Engine.Instance.GraphicsDevice.Viewport;
                        Vector2 Delta = Engine.Instance.InputManager.GetMouseDifference();

                        Vector3 StartPosition = Viewport.Project(Vector3.Zero, Projection, View, Translation);
                        Vector3 EndPosition = Viewport.Project(UnitAxis, Projection, View, Translation);

                        Vector3 ScreenDirection = Vector3.Normalize(EndPosition - StartPosition);
                        EndPosition = StartPosition + (ScreenDirection * (Vector3.Dot(new Vector3(Delta, 0f), ScreenDirection)));

                        StartPosition = Viewport.Unproject(StartPosition, Projection, View, Translation);
                        EndPosition = Viewport.Unproject(EndPosition, Projection, View, Translation);

                        Vector3 Difference = EndPosition - StartPosition;

                        switch (Mode)
                        {
                            case ManipulationMode3D.Translation:
                                SelectedWorldObject.Position += Difference;
                                break;
                            case ManipulationMode3D.Scale:
                                SelectedWorldObject.Scale += Difference;
                                break;
                            case ManipulationMode3D.UniformScale:
                                SelectedWorldObject.Scale += new Vector3(Vector3Util.Average(Difference));
                                break;

                        }
                    }
                }
                else
                {
                    Manipulating = false;
                }
            }

            XMani.Draw();
            XMani.Position = Position + new Vector3(RelativeScaleOverTwo, 0, 0);
            YMani.Draw();
            YMani.Position = Position + new Vector3(0, RelativeScaleOverTwo, 0);
            ZMani.Draw();
            ZMani.Position = Position + new Vector3(0, 0, RelativeScaleOverTwo);

            device.SetRenderTarget(PickerTarget);
            device.Clear(Color.Transparent);

            if (SelectedWorldObject != null)
            {
                device.DepthStencilState = DepthStencilState.Default;

                float Nin = MathHelper.ToRadians(90);
                Matrix ScaleMatrix = Matrix.CreateScale(RelativeScale);
                PickingEffect.Parameters["World"].SetValue(ScaleMatrix * Matrix.CreateRotationX(Nin) * Matrix.CreateTranslation(SelectedWorldObject.Position + new Vector3(0, 0, 2.5f * RelativeScale)));
                PickingEffect.Parameters["Color"].SetValue(new Vector3(0, 0, 1));
                DrawBrainModel(this.Cylinder);

                PickingEffect.Parameters["World"].SetValue(ScaleMatrix * Matrix.CreateTranslation(SelectedWorldObject.Position + new Vector3(0, 2.5f * RelativeScale, 0)));
                PickingEffect.Parameters["Color"].SetValue(new Vector3(0, 1, 0));
                DrawBrainModel(this.Cylinder);

                PickingEffect.Parameters["World"].SetValue(ScaleMatrix * Matrix.CreateRotationZ(Nin) * Matrix.CreateTranslation(SelectedWorldObject.Position - new Vector3(2.5f * RelativeScale, 0, 0)));
                PickingEffect.Parameters["Color"].SetValue(new Vector3(1, 0, 0));
                DrawBrainModel(this.Cylinder);
            }

            device.SetRenderTarget(null);
        }


        public IPickedObject Pick(int X, int Y, Viewport viewport, ICamera3D Camera, out Vector3 Axis)
        {
            Axis = Vector3.Zero;

            Ray MouseRay = MakeMouseRay(X, Y, viewport, Camera);

            float? box = MouseRay.Intersects(this.XMani.BoundingBox);
            float? box1 = MouseRay.Intersects(this.YMani.BoundingBox);
            float? box2 = MouseRay.Intersects(this.ZMani.BoundingBox);

            if (box != null)
            {
                return XMani;
            }
            else if (box1 != null)
            {
                return YMani;
            }
            else if (box2 != null)
            {
                return ZMani;
            }

            RayTestData rayData;
            if (Engine.Instance.Physics3DManager.RayTest(MouseRay, out rayData))
            {
                if (rayData.PhysicObject != null)
                {
                    //this.SelectedWorldObject = rayData.PhysicObject as IPickedObject;
                    return HitPicked(rayData);
                }
            }

            return null;
        }

        protected virtual IPickedObject HitPicked(RayTestData data)
        {
            throw new NotImplementedException();
        }

        public Ray MakeMouseRay(int X, int Y, Viewport viewport, ICamera3D camera)
        {
            Vector2 Position = new Vector2(X, Y);
            Vector3 nearSource = new Vector3(Position, 0f);
            Vector3 farSource = new Vector3(Position, 1f);

            Vector3 nearPoint = viewport.Unproject(nearSource,
                camera.Projection, camera.View, Matrix.Identity);

            Vector3 farPoint = viewport.Unproject(farSource,
                camera.Projection, camera.View, Matrix.Identity);

            Vector3 direction = farPoint - nearPoint;
            if (direction != Vector3.Zero)
            {
                direction.Normalize();
            }

            return new Ray(nearPoint, direction);
        }


        public bool ShouldDraw { get; set; }

        public void Draw()
        {
        }


        public void EndDraw()
        {
            batch.Begin();
            batch.Draw(this.PickerTarget, Vector2.Zero, Color.White);
            batch.End();
        }

        private void DrawBrainModel(BrainModel model)
        {
            GraphicsDevice device = Engine.Instance.GraphicsDevice;
            foreach (BrainModelMesh mesh in model.Meshes)
            {
                if (mesh.IndexBuffer != null &&
                    mesh.IndexBuffer.IsDisposed ||
                    mesh.VertexBuffer.IsDisposed)
                {
                    return;
                }

                device.Indices = mesh.IndexBuffer;
                device.SetVertexBuffer(mesh.VertexBuffer);

                int count = this.PickingEffect.CurrentTechnique.Passes.Count;

                for (int p = 0; p < count; p++)
                {
                    PickingEffect.CurrentTechnique.Passes[p].Apply();

                    if (mesh.IndexBuffer == null)
                        device.DrawPrimitives(PrimitiveType.TriangleList, 0, mesh.PrimitiveCount);
                    else
                        device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0,
                            mesh.NumVertices, mesh.VertexOffset, mesh.PrimitiveCount);
                }
            }
        }


        public void EnableTerrainEditting()
        {
            throw new NotImplementedException();
        }


        public void SetTerrainEdittingStrength(float strength)
        {
            throw new NotImplementedException();
        }

        public void SetTerrainEdittingSize(float size)
        {
            throw new NotImplementedException();
        }


        public void LessGrid()
        {
            throw new NotImplementedException();
        }

        public void MoreGrid()
        {
            throw new NotImplementedException();
        }
    }
}
